package com.dhcc.core.framework.security.client.form;

import com.dhcc.core.config.properties.SysProperties;
import com.dhcc.core.framework.cache.SysCache;
import com.dhcc.core.framework.constant.state.ManagerStatus;
import com.dhcc.core.framework.exception.BizException;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.framework.util.HttpContextUtil;
import com.dhcc.core.framework.util.SpringContextHolder;
import com.dhcc.core.framework.util.encrypt.RSAUtil;
import com.dhcc.core.modules.system.entity.User;
import com.dhcc.core.modules.system.service.IUserService;
import com.google.code.kaptcha.Constants;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.UsernamePasswordCredentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
import org.pac4j.core.profile.CommonProfile;
import org.pac4j.core.util.CommonHelper;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;

import java.net.URLDecoder;

/**
 * 验证器
 */
public class FormAuthenticator implements Authenticator<UsernamePasswordCredentials> {

    private String retryLimitCacheName = "retry-limit-cache";
    private int retryFreezeTime;
    private int maxRetryLimit;

    @Override
    public void validate(final UsernamePasswordCredentials credentials, final WebContext context) {
        if (credentials == null) {
            throw new CredentialsException("用户名密码错误！");
        }
        String username = credentials.getUsername();
        String password = credentials.getPassword();
        String remember = context.getRequestParameter("remember");
        // 解密密码，需要先对特殊字符进行处理
        try {
            password = URLDecoder.decode(password, "UTF-8");
            password = RSAUtil.decryptCustomizePrivate(password);
        } catch (Exception e) {
            throw new BizException("密码处理失败，请联系管理员");
        }
        maxRetryLimit = SysProperties.me().getMaxRetryLimit();
        retryFreezeTime = SysProperties.me().getRetryFreezeTime();
        // 检测登录次数
        if (maxRetryLimit != 0 && retryFreezeTime != 0) {
            Cache passwordRetryCache = SysCache.me().dynaConfigCache(retryLimitCacheName, retryFreezeTime);
            // 获取用户登录次数
            ValueWrapper retryCount = passwordRetryCache.get(username);
            Integer count = 1;
            if (retryCount == null) {
                // 如果用户没有登陆过,登陆次数加1 并放入缓存
                passwordRetryCache.put(username, count);
            } else {
                // 加一次
                count = (Integer) retryCount.get() + 1;
                // 缓存次数
                passwordRetryCache.put(username, count);
                if (count > maxRetryLimit) {
                    throw new CredentialsException("超过" + maxRetryLimit + "次，请" + retryFreezeTime / 60 + "分钟后重试。");
                }
            }
        }

        // 验证验证码是否正确
        if (SysProperties.me().getKaptchaOpen()) {
            String kaptcha = context.getRequestParameter("kaptcha").trim();
            String code = (String) HttpContextUtil.getRequest().getSession(false).getAttribute(Constants.KAPTCHA_SESSION_KEY);
            if (CommonUtil.isEmpty(kaptcha) || !kaptcha.equals(code)) {
                throw new CredentialsException("验证码错误！");
            }
        }
        if (CommonHelper.isBlank(username)) {
            throw new CredentialsException("用户名密码错误！");
        }
        if (CommonHelper.isBlank(password)) {
            throw new CredentialsException("用户名密码错误！");
        }
        IUserService userService = SpringContextHolder.getBean(IUserService.class);
        User user = userService.authenticate(username, password);
        // 账号密码不对
        if (null == user) {
            throw new CredentialsException("用户名密码错误！");
        }
        // 账号被冻结
        if (user.getStatus() != ManagerStatus.OK.getCode()) {
            throw new LockedAccountException("系统中工号为：" + username + " 的账号已被冻结");
        }

        // 如果需要限制且验证成功，清除计数器缓存
        if (maxRetryLimit != 0 && retryFreezeTime != 0) {
            Cache passwordRetryCache = SysCache.me().dynaConfigCache(retryLimitCacheName, retryFreezeTime);
            // 清空计数器缓存
            passwordRetryCache.evict(username);
        }

        // 生成user profile
        final CommonProfile profile = new CommonProfile();
        profile.setId(username);
        if ("true".equals(remember)) {
            profile.setRemembered(true);
        }
        profile.addAttribute(Pac4jConstants.USERNAME, username);
        credentials.setUserProfile(profile);
    }
}
